/*************************************************************************
 *                                                                       *
 * This file is part of the DogosFrame distribution.  For full copyright *
 * information, see COPYRIGHT and COPYING.LESSER.                        *
 *                                                                       *
 * Author:           sqbang                                              *
 * Email:            sqbang@ustc.edu                                     *
 *                                                                       *
 *************************************************************************/

#ifndef DOGOS_include_COMMON_tbox_Logger_h
#define DOGOS_include_COMMON_tbox_Logger_h

//COMMON headers
#include "COMMON/tbox/StartupShutdownManager.h"

//C++ headers
#include <string>

namespace DOGOS
{

/**
 * Logger is a Singleton class for logging error, debug, and warning messages.
 *
 * The log_abort, log_warning, and log_debug methods are used to log a
 * message coming from a file and line.
 *
 * Warning and Debug messages can be turned on/off using the
 * set_warning and set_debug methods.  Abort messages may not be turned
 * off.
 *
 * Applications may override the logging mechanism.The basic idea is
 * the singleton Logger directs log messages to the appropriate
 * Appender which is responsible for writing the log message.  The
 * Appender is the destination for the log message.  Users may supply
 * implementors of the Appender interface to log the messages to
 * different I/O streams or elsewhere.  In this way applications can
 * redirect DOGOS generated messages to that applications logging
 * mechanism.  Appenders may be provided for abort, warning, and/or
 * debug messages.  The same Appender may be used for all messages.
 *
 *
 * For example to log to a stream simply inherit from LoggerAppender and
 * implement the logMesage method:
 * \code
 *
 *   class StreamAppender : public tbox::Logger::Appender {
 *
 *   public:
 *
 *      StreamAppender(ostream *stream) {
 *         d_stream = stream;
 *      }
 *
 *      void logMessage(const std::string &message,
 *                 const std::string &file_name,
 *                 const int line)
 *      {
 *         (*d_stream) << "At :" << file_name << " line :" << line
 *                     << " message: " << message << std::endl;
 *      }
 *
 *   private:
 *      ostream *d_stream;
 *   };
 * \endcode
 *
 *
 * This Appender could be use to log warning message using:
 * const boost::shared_ptr<tbox::Logger::Appender> appender = new ConsoleAppender()
 * tbox::Logger.get_instance() -> set_warning_appender(appender);
 *
 * Normally this would be done at the start of an application.
 *
 */
class Logger
{
public:

    /**
     * Interface for class that does the logging for the Logger.
     */
    class Appender
    {
    public:
        /**
         * Log a message with file and location information.
         */
        virtual void
        logMessage(
            const std::string& message,
            const std::string& file_name,
            const int line) = 0;

        virtual ~Appender();
    };

    /**
     * Gets the instance of the singleton logger.
     */
    static Logger *
    get_instance();

    /**
     * Logs an abort message with file & location
     */
    inline void
    log_abort(
        const std::string& message,
        const std::string& file_name,
        const int line);

    /**
     * Logs warning message with file & location.
     */
    inline void
    log_warning(
        const std::string& message,
        const std::string& file_name,
        const int line);

    /**
     * Logs debug message with file & location.
     */
    inline void
    log_debug(
        const std::string& message,
        const std::string& file_name,
        const int line);

    /**
     * Set the Appender for logging abort messages to an
     * application specific class.
     *
     * Default is to log to perr.
     */
    inline void
    set_abort_appender(
        Appender* appender);

    /**
     * Set the Appender for logging warning messages to an
     * application specific class.
     *
     * Default is to log to plog.
     */
    inline void
    set_warning_appender(
        Appender* appender);

    /**
     * Set the Appender for logging debug messages to an
     * application specific class.
     *
     * Default is to log to plog.
     */
    inline void
    set_debug_appender(
        Appender* appender);

    /**
     * Turn logging of warning messages on or off.
     *
     * Default is on.
     */
    inline void
    set_warning(
        bool onoff);

    /**
     * Turn logging of debug messages on or off.
     *
     * Default is off.
     */
    inline void
    set_debug(
        bool onoff);

private:

    /*
     * Private constructor to avoid construction of the singleton
     * outside this class.
     */
    Logger();

    /*
     * Private destructor to avoid destruction of the singleton
     * outside this class.
     */
    ~Logger();

    /**
     * Frees instance of the singleton logger.
     *
     * NOTE: should be called by StartupShutdownManager only.
     */
    static void
    finalize_callback();

private:

    /*
     * Instance of the singleton.
     */
    static Logger* s_instance;

    /*
     * Appenders for each type of logging.
     */
    Appender* d_abort_appender;
    Appender* d_warning_appender;
    Appender* d_debug_appender;

    /*
     * Logging state (on or off)
     */
    bool d_log_warning;
    bool d_log_debug;

    static StartupShutdownManager::Handler s_finalize_handler;

private:

    /*
     * do NOT use DISALLOWABLE_COPY_AND_ASSIGN macro, because it is in Common.h
     * and Logger.h is included in Common.h
     */
    Logger(const Logger&);
    void operator = (const Logger&);
};

}

#include "COMMON/tbox/Logger.inl"

#endif
